home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / TARGA.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-16  |  29.5 KB  |  1,379 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2. *                targa.c
  3. *
  4. *  This module contains the code to read and write the Targa output file
  5. *  format.
  6. *
  7. *  from Persistence of Vision(tm) Ray Tracer
  8. *  Copyright 1996 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. /****************************************************************************
  26. *
  27. *  Explanation:
  28. *
  29. *    -
  30. *
  31. *  ---
  32. *
  33. *  May 1994 : Support for 24-bit RLE Targa output files added: John Baily
  34. *             and David Payne.
  35. *
  36. *  Jul 1994 : Resume trace support and minor algorithm fix (one more still
  37. *             needed, see comments in Write_Targa_Line); resume will force
  38. *             Targa format to match the original trace format -- the T or C
  39. *             format flag is adjusted as necessary: Charles Marslett,
  40. *
  41. *  Jun 1995 : Added support for 32-bit Targa input and output files.
  42. *             The alpha channel has a value of 0 for 100% transparency
  43. *             and a value of 255 for 0% transparency. [DB]
  44. *
  45. *****************************************************************************/
  46.  
  47. #include "frame.h"
  48. #include "povproto.h"
  49. #include "povray.h"
  50. #include "targa.h"
  51.  
  52.  
  53.  
  54. /*****************************************************************************
  55. * Local preprocessor defines
  56. ******************************************************************************/
  57.  
  58. #define boolean  int
  59.  
  60.  
  61.  
  62. /*****************************************************************************
  63. * Local typedefs
  64. ******************************************************************************/
  65.  
  66. typedef struct pix
  67. {
  68.   DBL blue, green, red, transm;
  69. } pix;
  70.  
  71.  
  72.  
  73. /*****************************************************************************
  74. * Local variables
  75. ******************************************************************************/
  76.  
  77. static int Targa_Line_Number;
  78. static unsigned char idbuf[256];
  79.  
  80.  
  81.  
  82. /*****************************************************************************
  83. * Static functions
  84. ******************************************************************************/
  85.  
  86. static void convert_targa_color PARAMS((IMAGE_COLOUR *, unsigned, unsigned char *));
  87. static int Open_Targa_File PARAMS((FILE_HANDLE *handle, char *name, int *width, 
  88.                                    int *height, int buffer_size, int mode));
  89. static void Write_Targa_Line PARAMS((FILE_HANDLE *handle, COLOUR *line_data,
  90.                                      int line_number));
  91. static int Read_Targa_Line PARAMS((FILE_HANDLE *handle, COLOUR *line_data,
  92.                                    int *line_number));
  93. static void Close_Targa_File PARAMS((FILE_HANDLE *handle));
  94. static void Write_Targa_Pixel PARAMS((FILE_HANDLE *handle, DBL b, DBL g, DBL r,
  95.                                       DBL f));
  96.  
  97.  
  98.  
  99. /*****************************************************************************
  100. *
  101. * FUNCTION
  102. *
  103. *   Get_Targa_File_Handle
  104. *
  105. * INPUT
  106. *   
  107. * OUTPUT
  108. *   
  109. * RETURNS
  110. *   
  111. * AUTHOR
  112. *
  113. *   POV-Ray Team
  114. *   
  115. * DESCRIPTION
  116. *
  117. *   -
  118. *
  119. * CHANGES
  120. *
  121. *   -
  122. *
  123. ******************************************************************************/
  124.  
  125. FILE_HANDLE *Get_Targa_File_Handle()
  126. {
  127.   FILE_HANDLE *handle;
  128.  
  129.   handle = (FILE_HANDLE *)POV_MALLOC(sizeof(FILE_HANDLE), "TGA file handle");
  130.  
  131.   handle->Open_File_p         = Open_Targa_File;
  132.   handle->Write_Line_p        = Write_Targa_Line;
  133.   handle->Read_Line_p         = Read_Targa_Line;
  134.   handle->Read_Image_p        = Read_Targa_Image;
  135.   handle->Close_File_p        = Close_Targa_File;
  136.  
  137.   handle->file = NULL;
  138.   handle->buffer = NULL;
  139.   handle->buffer_size = 0;
  140.  
  141.   return(handle);
  142. }
  143.  
  144.  
  145. /*****************************************************************************
  146. *
  147. * FUNCTION
  148. *
  149. *   Open_Targa_File
  150. *
  151. * INPUT
  152. *   
  153. * OUTPUT
  154. *   
  155. * RETURNS
  156. *   
  157. * AUTHOR
  158. *
  159. *   POV-Ray Team
  160. *   
  161. * DESCRIPTION
  162. *
  163. *   -
  164. *
  165. * CHANGES
  166. *
  167. *   Jun 1995 : Added code for 32 bit Targa files. [DB]
  168. *
  169. *   Sept 1995: Modified header output for Targa files. [AED]
  170. *
  171. ******************************************************************************/
  172.  
  173. static int Open_Targa_File (handle, name, width, height, buffer_size, mode)
  174. FILE_HANDLE *handle;
  175. char *name;
  176. int *width;
  177. int *height;
  178. int buffer_size;
  179. int mode;
  180. {
  181.   unsigned char tgaheader[18];
  182.  
  183.   handle->mode = mode;
  184.   handle->filename = name;
  185.  
  186.   Targa_Line_Number = 0;
  187.   
  188.   switch (mode)
  189.   {
  190.     case READ_MODE:
  191.  
  192.       /* We can't resume from stdout. */
  193.       if (opts.Options & TO_STDOUT ||
  194.           (handle->file = fopen(name, READ_FILE_STRING)) == NULL)
  195.       {
  196.         Status_Info("\n");
  197.         return(0);
  198.       }
  199.  
  200.       /* Read targa header information. */
  201.  
  202.       if (fread(tgaheader, 18, 1, handle->file) != 1)
  203.       {
  204.         return(0);
  205.       }
  206.  
  207.       /* Decipher the header information */
  208.  
  209.       switch (tgaheader[2])
  210.       {
  211.         case 2  : opts.OutputFormat = 'T'; break;
  212.         case 10 : opts.OutputFormat = 'C'; break;
  213.         default : return(0);
  214.       }
  215.  
  216.       switch (tgaheader[16])
  217.       {
  218.         case 24 : break;
  219.         case 32 : opts.Options |= OUTPUT_ALPHA; break;
  220.         default : return(0);
  221.       }
  222.  
  223.       /* First_Column set to x offset.  Bytes 8, 9 */
  224.       opts.First_Column = tgaheader[8] + (tgaheader[9] << 8);
  225.  
  226.       /* First line set to y offset.  Bytes 10, 11 */
  227.       opts.First_Line = Targa_Line_Number = tgaheader[10] + (tgaheader[11]<<8);
  228.  
  229.       handle->width  = *width  = tgaheader[12] + (tgaheader[13] << 8);
  230.       handle->height = *height = tgaheader[14] + (tgaheader[15] << 8);
  231.  
  232.       handle->buffer_size = buffer_size;
  233.   
  234.       Status_Info("\nResuming interrupted trace from %s",handle->filename);
  235.  
  236.       break;
  237.  
  238.     case WRITE_MODE:
  239.  
  240.       if (opts.Options & TO_STDOUT)
  241.       {
  242.         buffer_size = 0;
  243.         handle->file = stdout;
  244.       }
  245.       else if ((handle->file = fopen (name, WRITE_FILE_STRING)) == NULL)
  246.       {
  247.         return(0);
  248.       }
  249.  
  250.       if (buffer_size != 0)
  251.       {
  252.         handle->buffer = POV_MALLOC((size_t)buffer_size, "TGA file buffer");
  253.         setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size);
  254.       }
  255.  
  256.       /* Output TGA file header info */
  257.       putc(0, handle->file);  /* Byte 0 - Length of Image ID field */
  258.  
  259.       putc(0, handle->file);  /* Byte 1 - Color map type (0 is no color map) */
  260.  
  261.       switch(opts.OutputFormat)  /* Byte 2 - TGA file type */
  262.       {
  263.         case 't': /* Uncompressed True-Color Image */
  264.         case 'T': 
  265.         case 's': 
  266.         case 'S': putc(2, handle->file); break;
  267.  
  268.         case 'c': /* Run-length compressed True-Color Image */
  269.         case 'C': putc(10, handle->file); break;
  270.       }
  271.  
  272.       putc(0, handle->file);  /* Byte 3 - Index of first color map entry LSB */
  273.       putc(0, handle->file);  /* Byte 4 - Index of first color map entry MSB */
  274.  
  275.       putc(0, handle->file);  /* Byte 5 - Color map length LSB */
  276.       putc(0, handle->file);  /* Byte 6 - Color map legth MSB */
  277.  
  278.       putc(0, handle->file);  /* Byte 7 - Color map size */
  279.  
  280.       /* x origin set to "First_Column"  Bytes 8, 9 */
  281.  
  282.       putc(opts.First_Column % 256, handle->file);
  283.       putc(opts.First_Column / 256, handle->file);
  284.  
  285.       /* y origin set to "First_Line"    Bytes 10, 11 */
  286.  
  287.       putc(opts.First_Line % 256, handle->file);
  288.       putc(opts.First_Line / 256, handle->file);
  289.  
  290.       /* write width and height  Bytes 12 - 15 */
  291.  
  292.       putc(*width % 256, handle->file);
  293.       putc(*width / 256, handle->file);
  294.       putc(*height % 256, handle->file);
  295.       putc(*height / 256, handle->file);
  296.  
  297.       /* We write 24 or 32 bits/pixel (16 million colors and alpha channel)
  298.        * and also store the orientation and Alpha channel depth.  Bytes 16, 17.
  299.        */
  300.       if (opts.Options & OUTPUT_ALPHA)
  301.       {
  302.         putc(32, handle->file);    /* 32 bits/pixel (BGRA) */
  303.         putc(0x28, handle->file);  /* Data starts at top left, 8 bits Alpha */
  304.       }
  305.       else
  306.       {
  307.         putc(24, handle->file);    /* 24 bits/pixel (BGR) */
  308.         putc(0x20, handle->file);  /* Data starts at top left, 0 bits Alpha */
  309.       }
  310.  
  311.       /* TGA file Image ID field data would go here (up to 255 chars) */
  312.  
  313.       handle->width = *width;
  314.       handle->height = *height;
  315.  
  316.       handle->buffer_size = buffer_size;
  317.  
  318.       break;
  319.  
  320.     case APPEND_MODE:
  321.  
  322.       if (opts.Options & TO_STDOUT)
  323.       {
  324.         buffer_size = 0;
  325.         handle->file = stdout;
  326.       }
  327.       else if ((handle->file = fopen (name, APPEND_FILE_STRING)) == NULL)
  328.       {
  329.         return(0);
  330.       }
  331.       else if (buffer_size != 0)
  332.       {
  333.         handle->buffer = POV_MALLOC((size_t)buffer_size, "TGA file buffer");
  334.         setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size);
  335.       }
  336.  
  337.       break;
  338.   }
  339.  
  340.   return(1);
  341. }
  342.  
  343.  
  344.  
  345. /*****************************************************************************
  346. *
  347. * FUNCTION
  348. *
  349. *   Write_Targa_Pixel
  350. *
  351. * INPUT
  352. *
  353. *   handle     - Current file handel
  354. *   r, g, b, f - Color values to write
  355. *   
  356. * OUTPUT
  357. *   
  358. * RETURNS
  359. *   
  360. * AUTHOR
  361. *
  362. *   Dan Farmer
  363. *   
  364. * DESCRIPTION   :
  365. *
  366. *   Moves redundant code to a single function.  Adding 16 bit grayscale
  367. *   conditional code to each occurance of writing a pixel was getting a bit
  368. *   too wordy.
  369. *
  370. * CHANGES
  371. *
  372. *   Jun 1995 : Added code for 32 bit Targa files. [DB]
  373. *
  374. *   Sept 1995: Modified handling of Alpha channel to use only opts.Options
  375. *   Sept 1995: Modified handling of grayscale to use only opts.Options
  376. *
  377. ******************************************************************************/
  378.  
  379. static void Write_Targa_Pixel (handle, b, g, r, f)
  380. FILE_HANDLE *handle;
  381. DBL r, g, b, f;
  382. {
  383.   unsigned int gray;
  384.  
  385.   if (opts.Options & HF_GRAY_16)
  386.   {
  387.     /* Ouput heightfield in POV red/green format */
  388.     gray = ((0.30 * r) + (0.59 * g) + (0.11 * b)) * 65535;
  389.  
  390.     if ((putc(0 , handle->file) == EOF) ||
  391.         (putc(gray & 0xFF, handle->file) == EOF) ||
  392.         (putc((gray >> 8) & 0xFF, handle->file) == EOF))
  393.     {
  394.       Error("Error writing TGA output data to %s.\n",handle->filename);
  395.     }
  396.   }
  397.   else
  398.   {
  399.     /* Normal 24/32 bit pixel coloring */
  400.  
  401.     if ((putc((int) floor(b * 255.0), handle->file) == EOF) ||
  402.         (putc((int) floor(g * 255.0), handle->file) == EOF) ||
  403.         (putc((int) floor(r * 255.0), handle->file) == EOF))
  404.     {
  405.       Error("Error writing TGA output data to %s.\n",handle->filename);
  406.     }
  407.  
  408.     if (opts.Options & OUTPUT_ALPHA)
  409.     {
  410.       if (putc((int) floor((1.0 - f) * 255.0), handle->file) == EOF)
  411.       {
  412.         Error("Error writing TGA output data to %s.\n",handle->filename);
  413.       }
  414.     }
  415.   }
  416. }
  417.  
  418.  
  419. /*****************************************************************************
  420. *
  421. * FUNCTION
  422. *
  423. *   Write_Targa_Line
  424. *
  425. * INPUT
  426. *   
  427. * OUTPUT
  428. *   
  429. * RETURNS
  430. *   
  431. * AUTHOR
  432. *
  433. *   POV-Ray Team
  434. *   
  435. * DESCRIPTION
  436. *
  437. *   -
  438. *
  439. * CHANGES
  440. *
  441. *   Jun 1995 : Added code for 32 bit Targa files. [DB]
  442. *
  443. ******************************************************************************/
  444.  
  445. static void Write_Targa_Line (handle, line_data, line_number)
  446. FILE_HANDLE *handle;
  447. COLOUR *line_data;
  448. int line_number;
  449. {
  450.   register int x;
  451.   int ptype, cnt, llen, startx;
  452.   boolean writenow;
  453.   pix curpix, nexpix;
  454.  
  455.   switch (opts.OutputFormat)
  456.   {
  457.     case 't':
  458.     case 'T':
  459.     case 's':
  460.     case 'S':
  461.  
  462.       for (x = 0; x < handle->width; x++)
  463.       {
  464.         Write_Targa_Pixel (handle, line_data[x][BLUE], line_data[x][GREEN], line_data[x][RED], line_data[x][TRANSM]);
  465.       }
  466.  
  467.       break;
  468.  
  469.     case 'c':
  470.     case 'C':
  471.  
  472.       llen = handle->width;
  473.  
  474.       startx = 0;
  475.  
  476.       cnt = 1;
  477.  
  478.       curpix.blue   = line_data[startx][BLUE];
  479.       curpix.green  = line_data[startx][GREEN];
  480.       curpix.red    = line_data[startx][RED];
  481.       curpix.transm = line_data[startx][TRANSM];
  482.  
  483.       ptype = 0;
  484.  
  485.       writenow = FALSE;
  486.  
  487.       for (;;)
  488.       {
  489.         nexpix.blue   = line_data[startx+cnt][BLUE];
  490.         nexpix.green  = line_data[startx+cnt][GREEN];
  491.         nexpix.red    = line_data[startx+cnt][RED];
  492.         nexpix.transm = line_data[startx+cnt][TRANSM];
  493.  
  494.         if ((nexpix.red == curpix.red) && (nexpix.blue == curpix.blue) &&
  495.             (nexpix.green == curpix.green) && (nexpix.transm == curpix.transm))
  496.         {
  497.           if (ptype == 0)
  498.           {
  499.             cnt++;
  500.  
  501.             if ((cnt >= 128) || ((startx + cnt) >= llen))
  502.             {
  503.               writenow = TRUE;
  504.             }
  505.           }
  506.           else
  507.           {
  508.             cnt--;
  509.  
  510.             writenow = TRUE;
  511.           }
  512.         }
  513.         else
  514.         {
  515.           if ((ptype == 1) || (cnt <= 1))
  516.           {
  517.             ptype = 1;
  518.  
  519.             curpix = nexpix;
  520.  
  521.             cnt++;
  522.  
  523.             if ((cnt >= 128) || ((startx + cnt) >= llen))
  524.             {
  525.               writenow = TRUE;
  526.             }
  527.           }
  528.           else
  529.           {
  530.             writenow = TRUE;
  531.           }
  532.         }
  533.  
  534.         if (writenow)
  535.         {
  536.           /* This test SHOULD be unnecessary!  However, it isn't!  [CWM] */
  537.  
  538.           if (startx + cnt > llen)
  539.           {
  540.             cnt = llen - startx;
  541.           }
  542.  
  543.           if (ptype == 0)
  544.           {
  545.             putc((int) ((cnt - 1) | 0x80), handle->file);
  546.  
  547.             Write_Targa_Pixel (handle, curpix.blue, curpix.green, curpix.red, curpix.transm);
  548.  
  549.             curpix = nexpix;
  550.           }
  551.           else
  552.           {
  553.             putc((int) cnt - 1, handle->file);
  554.  
  555.             for (x = 0; x < cnt; x++)
  556.             {
  557.                Write_Targa_Pixel (handle,
  558.                  line_data[startx+x][BLUE], line_data[startx+x][GREEN],
  559.                  line_data[startx+x][RED], line_data[startx+x][TRANSM]);
  560.             }
  561.           }
  562.           startx = startx + cnt;
  563.  
  564.           writenow = FALSE;
  565.  
  566.           ptype = 0;
  567.  
  568.           cnt = 1;
  569.  
  570.           if (startx >= llen)
  571.           {
  572.              break; /* Exit while */
  573.           }
  574.         }
  575.       }
  576.  
  577.       break; /* End of case */
  578.   }
  579.  
  580.   if (handle->buffer_size == 0)
  581.   {
  582.     /* Close and reopen file (if not stdout) for integrity in case we crash */
  583.  
  584.     fflush(handle->file);
  585.  
  586.     if (!(opts.Options & TO_STDOUT))
  587.     {
  588.       handle->file = freopen(handle->filename, APPEND_FILE_STRING, handle->file);
  589.     }
  590.   }
  591. }
  592.  
  593.  
  594.  
  595. /*****************************************************************************
  596. *
  597. * FUNCTION
  598. *
  599. *   Read_Targa_Line
  600. *
  601. * INPUT
  602. *   
  603. * OUTPUT
  604. *   
  605. * RETURNS
  606. *   
  607. * AUTHOR
  608. *
  609. *   POV-Ray Team
  610. *   
  611. * DESCRIPTION
  612. *
  613. *   -
  614. *
  615. * CHANGES
  616. *
  617. *   Jun 1995 : Added code for 32 bit Targa files. [DB]
  618. *
  619. ******************************************************************************/
  620.  
  621. static int Read_Targa_Line (handle, line_data, line_number)
  622. FILE_HANDLE *handle;
  623. COLOUR *line_data;
  624. int *line_number;
  625. {
  626.   int x, data, cnt;
  627.   DBL rdata, gdata, bdata, fdata;
  628.  
  629.   switch (opts.OutputFormat)
  630.   {
  631.     case 't':
  632.     case 'T':
  633.     case 's':
  634.     case 'S':
  635.  
  636.       for (x = 0; x < handle->width; x++)
  637.       {
  638.         /* Read the BLUE data byte.  If EOF is reached on the first
  639.          * character read, then this line hasn't been rendered yet.
  640.          * Return 0.  If an EOF occurs somewhere within the line, this
  641.          * is an error - return -1.
  642.          */
  643.  
  644.         if ((data = getc(handle->file)) == EOF)
  645.         {
  646.           if (x == 0)
  647.           {
  648.             return(0);
  649.           }
  650.           else
  651.           {
  652.             return(-1);
  653.           }
  654.         }
  655.  
  656.         line_data[x][BLUE] = (DBL) data / 255.0;
  657.  
  658.         /* Read the GREEN data byte. */
  659.  
  660.         if ((data = getc(handle->file)) == EOF)
  661.         {
  662.           return(-1);
  663.         }
  664.  
  665.         line_data[x][GREEN] = (DBL) data / 255.0;
  666.  
  667.         /* Read the RED data byte. */
  668.  
  669.         if ((data = getc(handle->file)) == EOF)
  670.         {
  671.           return(-1);
  672.         }
  673.  
  674.         line_data[x][RED] = (DBL) data / 255.0;
  675.  
  676.         /* Read alpha channel. */
  677.  
  678.         if (opts.Options & OUTPUT_ALPHA)
  679.         {
  680.           if ((data = getc(handle->file)) == EOF)
  681.           {
  682.             return(-1);
  683.           }
  684.  
  685.           line_data[x][TRANSM] = 1.0 - (DBL)data / 255.0;
  686.         }
  687.         else
  688.         {
  689.           line_data[x][TRANSM] = 0.0;
  690.         }
  691.       }
  692.  
  693.       break;
  694.  
  695.     case 'c':
  696.     case 'C':
  697.  
  698.       cnt = 0;
  699.  
  700.       do
  701.       {
  702.         if ((data = getc(handle->file)) == EOF)
  703.         {
  704.           if (cnt == 0)
  705.           {
  706.             return(0);
  707.           }
  708.           else
  709.           {
  710.             return(-1);
  711.           }
  712.         }
  713.  
  714.         if (data & 0x80)
  715.         {
  716.           x = data & 0x7F;
  717.  
  718.           if ((data = getc(handle->file)) == EOF)
  719.           {
  720.             return(-1);
  721.           }
  722.  
  723.           bdata = (DBL) data / 255.0;
  724.  
  725.           if ((data = getc(handle->file)) == EOF)
  726.           {
  727.             return(-1);
  728.           }
  729.  
  730.           gdata = (DBL) data / 255.0;
  731.  
  732.           if ((data = getc(handle->file)) == EOF)
  733.           {
  734.             return(-1);
  735.           }
  736.  
  737.           rdata = (DBL) data / 255.0;
  738.  
  739.           /* Read alpha channel if any. */
  740.  
  741.           if (opts.Options & OUTPUT_ALPHA)
  742.           {
  743.             if ((data = getc(handle->file)) == EOF)
  744.             {
  745.               return(-1);
  746.             }
  747.  
  748.             fdata = 1.0 - (DBL)data / 255.0;
  749.           }
  750.           else
  751.           {
  752.             fdata = 0.0;
  753.           }
  754.  
  755.           do
  756.           {
  757.             line_data[cnt][BLUE]   = bdata;
  758.             line_data[cnt][GREEN]  = gdata;
  759.             line_data[cnt][RED]    = rdata;
  760.             line_data[cnt][TRANSM] = fdata;
  761.  
  762.             cnt++;
  763.           }
  764.           while (--x != -1);
  765.         }
  766.         else
  767.         {
  768.           x = data & 0x7F;
  769.  
  770.           do
  771.           {
  772.             if ((data = getc(handle->file)) == EOF)
  773.             {
  774.               return(-1);
  775.             }
  776.  
  777.             bdata = (DBL) data / 255.0;
  778.  
  779.             if ((data = getc(handle->file)) == EOF)
  780.             {
  781.               return(-1);
  782.             }
  783.  
  784.             gdata = (DBL) data / 255.0;
  785.  
  786.             if ((data = getc(handle->file)) == EOF)
  787.             {
  788.               return(-1);
  789.             }
  790.  
  791.             rdata = (DBL) data / 255.0;
  792.  
  793.             /* Read alpha channel if any. */
  794.  
  795.             if (opts.Options & OUTPUT_ALPHA)
  796.             {
  797.               if ((data = getc(handle->file)) == EOF)
  798.               {
  799.                 return(-1);
  800.               }
  801.  
  802.               fdata = 1.0 - (DBL)data / 255.0;
  803.             }
  804.             else
  805.             {
  806.               fdata = 0.0;
  807.             }
  808.  
  809.             line_data[cnt][BLUE]   = bdata;
  810.             line_data[cnt][GREEN]  = gdata;
  811.             line_data[cnt][RED]    = rdata;
  812.             line_data[cnt][TRANSM] = fdata;
  813.  
  814.             cnt++;
  815.           }
  816.           while (--x != -1);
  817.         }
  818.       }
  819.       while (cnt < handle->width);
  820.  
  821.       if (cnt != handle->width)
  822.       {
  823.         return(-1);
  824.       }
  825.  
  826.       break;
  827.   }
  828.  
  829.   *line_number = Targa_Line_Number++;
  830.  
  831.   return(1);
  832. }
  833.  
  834.  
  835.  
  836. /*****************************************************************************
  837. *
  838. * FUNCTION
  839. *
  840. *   Close_Targa_File
  841. *
  842. * INPUT
  843. *   
  844. * OUTPUT
  845. *   
  846. * RETURNS
  847. *   
  848. * AUTHOR
  849. *
  850. *   POV-Ray Team
  851. *   
  852. * DESCRIPTION
  853. *
  854. *   -
  855. *
  856. * CHANGES
  857. *
  858. *   -
  859. *
  860. ******************************************************************************/
  861.  
  862. static void Close_Targa_File (handle)
  863. FILE_HANDLE *handle;
  864. {
  865.   if (handle->file)
  866.   {
  867.     fflush(handle->file);
  868.  
  869.     if (!(opts.Options & TO_STDOUT))
  870.       fclose (handle->file);
  871.   }
  872.  
  873.   if (handle->buffer != NULL)
  874.   {
  875.     POV_FREE (handle->buffer);
  876.   }
  877.  
  878.   handle->file = NULL;
  879.   handle->buffer = NULL;
  880. }
  881.  
  882.  
  883.  
  884. /*****************************************************************************
  885. *
  886. * FUNCTION
  887. *
  888. *   convert_targa_color
  889. *
  890. * INPUT
  891. *   
  892. * OUTPUT
  893. *   
  894. * RETURNS
  895. *   
  896. * AUTHOR
  897. *
  898. *   POV-Ray Team
  899. *   
  900. * DESCRIPTION
  901. *
  902. *   -
  903. *
  904. * CHANGES
  905. *
  906. *   -
  907. *
  908. ******************************************************************************/
  909.  
  910. static void convert_targa_color(tcolor, pixelsize, bytes)
  911. IMAGE_COLOUR *tcolor;
  912. unsigned pixelsize;
  913. unsigned char *bytes;
  914. {
  915.   switch (pixelsize)
  916.   {
  917.     case 1:
  918.  
  919.       tcolor->Red    = bytes[0];
  920.       tcolor->Green  = bytes[0];
  921.       tcolor->Blue   = bytes[0];
  922.       tcolor->Filter = 0;
  923.       tcolor->Transmit = 0;
  924.  
  925.       break;
  926.  
  927.     case 2:
  928.  
  929.       tcolor->Red    = ((bytes[1] & 0x7c) << 1);
  930.       tcolor->Green  = (((bytes[1] & 0x03) << 3) | ((bytes[0] & 0xe0) >> 5)) << 3;
  931.       tcolor->Blue   = (bytes[0] & 0x1f) << 3;
  932.       tcolor->Filter = 0;
  933.       tcolor->Transmit = 255 - (bytes[1] & 0x80 ? 255 : 0);
  934.  
  935.       break;
  936.  
  937.     case 3:
  938.  
  939.       tcolor->Red    = bytes[2];
  940.       tcolor->Green  = bytes[1];
  941.       tcolor->Blue   = bytes[0];
  942.       tcolor->Filter = 0;
  943.       tcolor->Transmit = 0;
  944.  
  945.       break;
  946.  
  947.     case 4:
  948.  
  949.       tcolor->Red    = bytes[2];
  950.       tcolor->Green  = bytes[1];
  951.       tcolor->Blue   = bytes[0];
  952.       tcolor->Filter = 0;
  953.       tcolor->Transmit = 255 - bytes[3];
  954.  
  955.       break;
  956.  
  957.     default:
  958.  
  959.       Error("Bad pixelsize in TGA color.\n");
  960.   }
  961. }
  962.  
  963.  
  964.  
  965. /*****************************************************************************
  966. *
  967. * FUNCTION
  968. *
  969. *   Read_Targa_Image
  970. *
  971. * INPUT
  972. *   
  973. * OUTPUT
  974. *   
  975. * RETURNS
  976. *   
  977. * AUTHOR
  978. *
  979. *   POV-Ray Team
  980. *   
  981. * DESCRIPTION
  982. *
  983. *   Reads a Targa image into an RGB image buffer.  Handles 8, 16, 24, 32 bit
  984. *   formats.  Raw or color mapped. Simple raster and RLE compressed pixel
  985. *   encoding. Right side up or upside down orientations.
  986. *
  987. * CHANGES
  988. *
  989. *   Jun 1995 : Added code for 32 bit Targa files. [DB]
  990. *
  991. ******************************************************************************/
  992.  
  993. void Read_Targa_Image(Image, name)
  994. IMAGE *Image;
  995. char *name;
  996. {
  997.   int h;
  998.   int temp;
  999.   unsigned i, j, k;
  1000.   unsigned char cflag = 0, *map_line = NULL, bytes[4], tgaheader[18];
  1001.   unsigned ftype, idlen, cmlen, cmsiz, psize, orien;
  1002.   unsigned width, height;
  1003.   FILE *filep;
  1004.   IMAGE_LINE *line_data = NULL;
  1005.   IMAGE_COLOUR *cmap, pixel;
  1006.  
  1007.   /* Start by trying to open the file */
  1008.  
  1009.   if ((filep = Locate_File(name, READ_FILE_STRING,".tga",".TGA",TRUE)) == NULL)
  1010.   {
  1011.     Error ("Error opening TGA image.\n");
  1012.   }
  1013.  
  1014.   if (fread(tgaheader, 18, 1, filep) != 1)
  1015.   {
  1016.     Error ("Error reading header of TGA image.\n");
  1017.   }
  1018.  
  1019.   /* Decipher the header information */
  1020.  
  1021.   idlen  = tgaheader[ 0];
  1022.   ftype  = tgaheader[ 2];
  1023.   cmlen  = tgaheader[ 5] + (tgaheader[ 6] << 8);
  1024.   cmsiz  = tgaheader[ 7] / 8;
  1025.   width  = tgaheader[12] + (tgaheader[13] << 8);
  1026.   height = tgaheader[14] + (tgaheader[15] << 8);
  1027.   psize  = tgaheader[16] / 8;
  1028.   orien  = tgaheader[17] & 0x20; /* Right side up ? */
  1029.  
  1030.   Image->iwidth  = width;
  1031.   Image->iheight = height;
  1032.   Image->width   = (DBL)width;
  1033.   Image->height  = (DBL)height;
  1034.   Image->Colour_Map_Size = cmlen;
  1035.   Image->Colour_Map = NULL;
  1036.  
  1037.   /* Determine if this is a supported Targa type */
  1038.  
  1039.   if (ftype == 9 || ftype == 10 || ftype == 11)
  1040.   {
  1041.     cflag = 1;
  1042.   }
  1043.   else
  1044.   {
  1045.     if (ftype == 1 || ftype == 2 || ftype == 3)
  1046.     {
  1047.       cflag = 0;
  1048.     }
  1049.     else
  1050.     {
  1051.       Error("Unsupported file type %d in TGA image.\n", ftype);
  1052.     }
  1053.   }
  1054.  
  1055.   /* Skip over the picture ID information */
  1056.  
  1057.   if (idlen > 0 && fread(idbuf, idlen, 1, filep) != 1)
  1058.   {
  1059.     Error ("Error reading header from TGA image.\n");
  1060.   }
  1061.  
  1062.   /* Read in the the color map (if any) */
  1063.  
  1064.   if (cmlen > 0)
  1065.   {
  1066.     if (psize != 1)
  1067.     {
  1068.       Error("Unsupported color map bit depth (%d bpp) in TGA image.\n",
  1069.             psize * 8);
  1070.     }
  1071.  
  1072.     cmap = (IMAGE_COLOUR *)POV_MALLOC(cmlen * sizeof(IMAGE_COLOUR), "TGA color map");
  1073.  
  1074.     for (i = 0; i < cmlen; i++)
  1075.     {
  1076.       for (j = 0; j < cmsiz; j++)
  1077.       {
  1078.         if ((temp = fgetc(filep)) == EOF)
  1079.         {
  1080.           Error("Error reading color map from TGA image.\n");
  1081.         }
  1082.         else
  1083.         {
  1084.           bytes[j] = (unsigned char)temp;
  1085.         }
  1086.       }
  1087.  
  1088.       convert_targa_color(&cmap[i], cmsiz, bytes);
  1089.     }
  1090.  
  1091.     Image->Colour_Map = cmap;
  1092.   }
  1093.   else
  1094.   {
  1095.     Image->Colour_Map = NULL;
  1096.   }
  1097.  
  1098.   /* Allocate the buffer for the image */
  1099.  
  1100.   if (cmlen > 0)
  1101.   {
  1102.     Image->data.map_lines = (unsigned char **)POV_MALLOC(height * sizeof(unsigned char *), "TGA image");
  1103.   }
  1104.   else
  1105.   {
  1106.     Image->data.rgb_lines = (IMAGE_LINE *)POV_MALLOC(height * sizeof(IMAGE_LINE), "TGA image");
  1107.   }
  1108.  
  1109.   for (i = 0; i < height; i++)
  1110.   {
  1111.     k = width * sizeof(unsigned char);
  1112.  
  1113.     if (cmlen > 0)
  1114.     {
  1115.       map_line = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line");
  1116.  
  1117.       Image->data.map_lines[i] = map_line;
  1118.     }
  1119.     else
  1120.     {
  1121.       line_data = &Image->data.rgb_lines[i];
  1122.  
  1123.       line_data->red    = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line");
  1124.       line_data->green  = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line");
  1125.       line_data->blue   = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line");
  1126.  
  1127.       if (psize > 3)
  1128.       {
  1129.         line_data->transm = (unsigned char *)POV_MALLOC((size_t)k, "TGA image line");
  1130.       }
  1131.       else
  1132.       {
  1133.         line_data->transm = (unsigned char *)NULL;
  1134.       }
  1135.     }
  1136.   }
  1137.  
  1138.   /* Read the image into the buffer */
  1139.  
  1140.   if (cflag)
  1141.   {
  1142.     /* RLE compressed images */
  1143.  
  1144.     if (cmlen > 0)
  1145.     {
  1146.       if (orien)
  1147.       {
  1148.         map_line = Image->data.map_lines[0];
  1149.       }
  1150.       else
  1151.       {
  1152.         map_line = Image->data.map_lines[height-1];
  1153.       }
  1154.     }
  1155.     else
  1156.     {
  1157.       if (orien)
  1158.       {
  1159.         line_data = &Image->data.rgb_lines[0];
  1160.       }
  1161.       else
  1162.       {
  1163.         line_data = &Image->data.rgb_lines[height-1];
  1164.       }
  1165.     }
  1166.  
  1167.     i = 0; /* row counter */
  1168.     j = 0; /* column counter */
  1169.  
  1170.     while (i < height)
  1171.     {
  1172.       /* Grab a header */
  1173.  
  1174.       if ((h = fgetc(filep)) == EOF)
  1175.       {
  1176.         Error("Error reading data from TGA image.\n");
  1177.       }
  1178.  
  1179.       if (h & 0x80)
  1180.       {
  1181.         /* Repeat buffer */
  1182.  
  1183.         h &= 0x7F;
  1184.  
  1185.         for (k = 0; k < psize; k++)
  1186.         {
  1187.           if ((temp = fgetc(filep)) == EOF)
  1188.           {
  1189.             Error("Error reading data from TGA image.\n");
  1190.           }
  1191.           else
  1192.           {
  1193.             bytes[k] = (unsigned char)temp;
  1194.           }
  1195.         }
  1196.  
  1197.         if (cmlen == 0)
  1198.         {
  1199.           convert_targa_color(&pixel, psize, bytes);
  1200.         }
  1201.  
  1202.         for (; h >= 0; h--)
  1203.         {
  1204.           if (cmlen > 0)
  1205.           {
  1206.             map_line[j] = bytes[0];
  1207.           }
  1208.           else
  1209.           {
  1210.             line_data->red[j]    = (unsigned char)pixel.Red;
  1211.             line_data->green[j]  = (unsigned char)pixel.Green;
  1212.             line_data->blue[j]   = (unsigned char)pixel.Blue;
  1213.             if (psize > 3)
  1214.             {
  1215.               line_data->transm[j] = (unsigned char)pixel.Transmit;
  1216.             }
  1217.           }
  1218.  
  1219.           if (++j == width)
  1220.           {
  1221.             i++;
  1222.  
  1223.             if (cmlen > 0)
  1224.             {
  1225.               if (orien)
  1226.               {
  1227.                 map_line = Image->data.map_lines[i];
  1228.               }
  1229.               else
  1230.               {
  1231.                 map_line = Image->data.map_lines[height-i-1];
  1232.               }
  1233.             }
  1234.             else
  1235.             {
  1236.               line_data += (orien ? 1 : -1);
  1237.             }
  1238.  
  1239.             j = 0;
  1240.           }
  1241.         }
  1242.       }
  1243.       else
  1244.       {
  1245.         /* Copy buffer */
  1246.  
  1247.         for (; h >= 0; h--)
  1248.         {
  1249.           for (k = 0; k < psize ; k++)
  1250.           {
  1251.             if ((temp = fgetc(filep)) == EOF)
  1252.             {
  1253.               Error("Error reading data from TGA image.\n");
  1254.             }
  1255.             else
  1256.             {
  1257.               bytes[k] = (unsigned char)temp;
  1258.             }
  1259.           }
  1260.  
  1261.           if (cmlen > 0)
  1262.           {
  1263.             map_line[j] = bytes[0];
  1264.           }
  1265.           else
  1266.           {
  1267.             convert_targa_color(&pixel, psize, bytes);
  1268.  
  1269.             line_data->red[j]    = (unsigned char)pixel.Red;
  1270.             line_data->green[j]  = (unsigned char)pixel.Green;
  1271.             line_data->blue[j]   = (unsigned char)pixel.Blue;
  1272.             if (psize > 3)
  1273.             {
  1274.               line_data->transm[j] = (unsigned char)pixel.Transmit;
  1275.             }
  1276.           }
  1277.  
  1278.           if (++j == width)
  1279.           {
  1280.             i++;
  1281.  
  1282.             if (cmlen > 0)
  1283.             {
  1284.               if (orien)
  1285.               {
  1286.                 map_line = Image->data.map_lines[i];
  1287.               }
  1288.               else
  1289.               {
  1290.                 map_line = Image->data.map_lines[height-i-1];
  1291.               }
  1292.             }
  1293.             else
  1294.             {
  1295.               line_data += (orien ? 1 : -1);
  1296.             }
  1297.  
  1298.             j = 0;
  1299.           }
  1300.         }
  1301.       }
  1302.     }
  1303.   }
  1304.   else
  1305.   {
  1306.     /* Simple raster image file, read in all of the pixels */
  1307.  
  1308.     if (cmlen == 0)
  1309.     {
  1310.       if (orien)
  1311.       {
  1312.         line_data = &Image->data.rgb_lines[0];
  1313.       }
  1314.       else
  1315.       {
  1316.         line_data = &Image->data.rgb_lines[height-1];
  1317.       }
  1318.     }
  1319.  
  1320.     for (i = 0; i < height; i++)
  1321.     {
  1322.       if (cmlen > 0)
  1323.       {
  1324.         if (orien)
  1325.         {
  1326.           map_line = Image->data.map_lines[i];
  1327.         }
  1328.         else
  1329.         {
  1330.           map_line = Image->data.map_lines[height-i-1];
  1331.         }
  1332.       }
  1333.  
  1334.       for (j = 0; j < width; j++)
  1335.       {
  1336.         for (k = 0; k < psize; k++)
  1337.         {
  1338.           if ((temp = fgetc(filep)) == EOF)
  1339.           {
  1340.             Error("Error reading data from TGA image.\n");
  1341.           }
  1342.           else
  1343.           {
  1344.             bytes[k] = (unsigned char)temp;
  1345.           }
  1346.         }
  1347.  
  1348.         if (cmlen > 0)
  1349.         {
  1350.           map_line[j] = bytes[0];
  1351.         }
  1352.         else
  1353.         {
  1354.           convert_targa_color(&pixel, psize, bytes);
  1355.  
  1356.           line_data->red[j]    = (unsigned char)pixel.Red;
  1357.           line_data->green[j]  = (unsigned char)pixel.Green;
  1358.           line_data->blue[j]   = (unsigned char)pixel.Blue;
  1359.           if (psize > 3)
  1360.           {
  1361.             line_data->transm[j] = (unsigned char)pixel.Transmit;
  1362.           }
  1363.         }
  1364.       }
  1365.  
  1366.       if (cmlen == 0)
  1367.       {
  1368.         line_data += (orien ? 1 : -1);
  1369.       }
  1370.     }
  1371.   }
  1372.  
  1373.   /* Any data following the image is ignored. */
  1374.  
  1375.   /* Close the image file */
  1376.  
  1377.   fclose(filep);
  1378. }
  1379.